package com.osce.ex.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.csce.domain.entity.exam.ExQuestinOption;
import com.csce.domain.entity.exam.ExQuestion;
import com.csce.domain.entity.exam.vo.QuestionExcelVo;
import com.doudou.core.str.StrUtil;
import com.doudou.core.throwable.GlobalException;
import com.douodu.excel.status.ImportStatus;
import com.osce.common.core.entity.AjaxResult;
import com.osce.common.utils.DateUtils;
import com.osce.ex.mapper.ExQuestionMapper;
import com.osce.ex.service.tools.ExQuestionCacheService;
import com.osce.interfaces.ex.IExQuestionService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 题目表Service业务层处理
 *
 * @author zzx
 * @since 2023-07-31
 */
@Service
public class ExQuestionServiceImpl extends ServiceImpl<ExQuestionMapper, ExQuestion> implements IExQuestionService {
    private static final Log log = LogFactory.get(IExQuestionService.class);

    @Resource
    ExQuestionCacheService cacheService;

    /**
     * 查询题目表
     *
     * @param id 题目表主键
     * @return 题目表
     */
    @Override
    public ExQuestion selectExQuestionById(Long id) {
        ExQuestion question;
        //先从缓存中获取
        if (ObjectUtil.isEmpty(question = cacheService.getCacheQuestion(id))) {
            question = baseMapper.selectExQuestionById(id);
            cacheService.cacheQuestion(question);
        }
        return question;
    }

    @Override
    public List<Map<Integer, Integer>> getQuestionIdsGroupByTopic() {
        return baseMapper.getQuestionIdsGroupByTopic();
    }


    /**
     * 查询题目表列表
     *
     * @param exQuestion 题目表
     * @return 题目表
     */
    @Override
    public List<ExQuestion> selectExQuestionList(ExQuestion exQuestion) {
        return baseMapper.selectExQuestionList(exQuestion);
    }

    /**
     * 新增题目表
     *
     * @param exQuestion 题目表
     * @return 结果
     */
    @Transactional
    @Override
    public int insertExQuestion(ExQuestion exQuestion) {
        //校验
        exQuestion.setCreateTime(DateUtils.getNowDate());
        int rows = baseMapper.insertExQuestion(exQuestion);
        insertExQuestinOption(exQuestion);
        cacheService.cacheQuestion(exQuestion);//缓存
        return rows;
    }

    /**
     * 修改题目表
     *
     * @param exQuestion 题目表
     * @return 结果
     */
    @Transactional
    @Override
    public int updateExQuestion(ExQuestion exQuestion) {
        baseMapper.deleteExQuestinOptionByQuestionId(exQuestion.getId());
        int i = baseMapper.updateExQuestion(exQuestion);
        insertExQuestinOption(exQuestion);
        cacheService.cacheQuestion(exQuestion);//缓存
        return i;
    }

    /**
     * 批量删除题目表
     *
     * @param ids 需要删除的题目表主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteExQuestionByIds(Long[] ids) {
        baseMapper.deleteExQuestinOptionByQuestionIds(ids);
        cacheService.delQuestion(ids);
        return baseMapper.deleteExQuestionByIds(ids);
    }

    /**
     * 删除题目表信息
     *
     * @param id 题目表主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteExQuestionById(Long id) {
        baseMapper.deleteExQuestinOptionByQuestionId(id);
        cacheService.delQuestion(id);
        return baseMapper.deleteExQuestionById(id);
    }

    /**
     * 导入
     */
    @Override
    public AjaxResult importData(List<QuestionExcelVo> questionList) {
        if (CollUtil.isEmpty(questionList)) {
            return AjaxResult.error("无法导入空数据");
        }
        ImportStatus importStatus = new ImportStatus();
        ExQuestion question;
        List<ExQuestinOption> answer;//答案
        int right;//对的选项的数量
        int index = 1;
        for (QuestionExcelVo q : questionList) {
            try {
                if (ObjectUtil.isEmpty(q.getTopic())) {
                    throw new RuntimeException("范畴不可为空");
                }
                if (ObjectUtil.isEmpty(q.getSubject())) {
                    throw new RuntimeException("科目不可为空");
                }
                if (ObjectUtil.isEmpty(q.getType())) {
                    throw new RuntimeException("类型不可为空");
                }
                if (StrUtil.isBlank(q.getContent())) {
                    throw new RuntimeException("内容不可为空");
                }
                if (StrUtil.isBlank(q.getAnswer())) {
                    throw new RuntimeException("答案不可为空");
                }
                question = BeanUtil.copyProperties(q, ExQuestion.class);
                //格式化答案
                answer = ListUtil.list(true);
                right = createAnswer(answer, q);
                //判断选项的数量
                if (answer.size() < 2) {
                    throw new GlobalException("至少需要两个选项");
                }
                //判断单选和多选
                if (question.getType().equals(1) && right != 1) {//单选
                    throw new GlobalException("单选题,至少且只需要一个答案");
                } else if (question.getType().equals(2) && right < 2) {//多选
                    throw new GlobalException("多选题,至少需要两个答案");
                }
                //插入数据
                question.setExQuestinOptionList(answer);
                insertExQuestion(question);
                importStatus.addSuccessMsg(index, "");
            } catch (Exception e) {
                importStatus.addFailError(index, e);
                log.error("", e);
            } finally {
                index++;
            }
        }
        return AjaxResult.success(importStatus.toHtmlString());
    }

    @Override
    public Integer selectCountByTopic(Integer topic) {
        return baseMapper.selectCountByTopic(topic);
    }

    @Override
    public List<Long> randomIdsByTopic(Map<Integer, Integer> map) {
        List<Long> list = ListUtil.list(false);
        map.forEach((topic, count) -> {
            List<Long> ids = baseMapper.selectIdsByTopic(topic);
            //随机生成不重复的长度在题目数量范围内的随机下标
            Set<Integer> set = new HashSet<>();
            while (set.size() < count) {
                set.add(RandomUtil.randomInt(0, ids.size()));
            }
            for (Integer index : set) {
                list.add(ids.get(index));
            }
        });
        return list;
    }


    /**
     * 格式化选项列表
     *
     * @param list     选项列表
     * @param question excel对象
     * @return 对的选项的数量
     * 如果中间间隔有空的数据，将忽略后续选项
     */
    private int createAnswer(List<ExQuestinOption> list, QuestionExcelVo question) {
        String answer = question.getAnswer();
        int right = 0;//对的选项的数量
        boolean r;//是否正确
        ExQuestinOption bean;
        if (StrUtil.isNotBlank(question.getA())) {
            r = StrUtil.containsIgnoreCase(answer, "A");
            bean = ExQuestinOption.builder().index("A").content(question.getA()).build();
            bean.setRight(r);
            list.add(bean);
            right += r ? 1 : 0;
        } else {
            return right;
        }
        if (StrUtil.isNotBlank(question.getB())) {
            r = StrUtil.containsIgnoreCase(answer, "B");
            bean = ExQuestinOption.builder().index("B").content(question.getB()).build();
            bean.setRight(r);
            list.add(bean);
            right += r ? 1 : 0;
        } else {
            return right;
        }
        if (StrUtil.isNotBlank(question.getC())) {
            r = StrUtil.containsIgnoreCase(answer, "C");
            bean = ExQuestinOption.builder().index("C").content(question.getC()).build();
            bean.setRight(r);
            list.add(bean);
            right += r ? 1 : 0;
        } else {
            return right;
        }
        if (StrUtil.isNotBlank(question.getD())) {
            r = StrUtil.containsIgnoreCase(answer, "D");
            bean = ExQuestinOption.builder().index("D").content(question.getD()).build();
            bean.setRight(r);
            list.add(bean);
            right += r ? 1 : 0;
        } else {
            return right;
        }
        return right;
    }

    /**
     * 新增题目选项表信息
     *
     * @param exQuestion 题目表对象
     */
    public void insertExQuestinOption(ExQuestion exQuestion) {
        List<ExQuestinOption> exQuestinOptionList = exQuestion.getExQuestinOptionList();
        Long id = exQuestion.getId();
        if (CollUtil.isNotEmpty(exQuestinOptionList)) {
            for (ExQuestinOption exQuestinOption : exQuestinOptionList) {
                exQuestinOption.setQuestionId(id);
            }
            baseMapper.batchExQuestinOption(exQuestinOptionList);
        }
    }
}
